import { Injectable } from '@nestjs/common';
import xlsx from 'node-xlsx';
import { Range } from 'xlsx';

interface Column {
  title: string;
  key: string;
  render?: (v: any, nearRow: any, row?: any) => any;
  arrayKey?: string;
}

@Injectable()
export class XlsxService {
  export(columns: Column[], list: any[]) {
    const data: any[] = [];
    let arrayKey = ''; // 数据中是否有数组需要渲染，意味着需要合并单元格
    let arrayKeyCount = 0;
    // 处理 header
    data.push(
      columns.map((i) => {
        if (i.arrayKey) {
          arrayKeyCount++;
          arrayKey = i.arrayKey;
        }
        return i.title;
      }),
    );
    // 处理数据
    if (arrayKey) {
      const ranges: Range[] = [];
      let mergeRow = 1;
      list.forEach((row) => {
        const arrayLength = row[arrayKey].length;
        row[arrayKey].forEach((arrayItem: any, i: number) => {
          data.push(
            columns.map((col) => {
              if (col.arrayKey) {
                const value = arrayItem[col.key];
                return col.render ? col.render(value, arrayItem, row) : value;
              }
              const value = row[col.key];
              return !i ? (col.render ? col.render(value, row) : value) : '';
            }),
          );
        });
        if (arrayLength > 1) {
          let mergeCol = 0; // 每个竖向单元格自己合并
          while (mergeCol < columns.length - arrayKeyCount) {
            // 列合并数小于不为array的列数
            ranges.push({
              s: { c: mergeCol, r: mergeRow },
              e: { c: mergeCol, r: mergeRow + arrayLength - 1 },
            });
            mergeCol++;
          }
          mergeRow += arrayLength;
        } else {
          mergeRow++;
        }
      });
      return xlsx.build(
        [
          {
            data,
            name: 'sheet',
            options: {
              '!merges': ranges,
            },
          },
        ],
      );
    }
    list.forEach((row) => {
      data.push(
        columns.map((col) => {
          const value = row[col.key];
          return col.render ? col.render(value, row) : value;
        }),
      );
    });

    return xlsx.build([{ data, name: 'sheet', options: {} }]);
  }
}
